metadata = read_tsv(here('data', 'metadata_merged.tsv'), col_types = cols()) %>%
         condition = str_c(CornVariety, FungalStrain, TissueExtraction, sep='_')) %>%
  rename(Corn_Genotype = CornVariety, Fungal_Treatment = FungalStrain, Tissue_Extraction = TissueExtraction)
get_counts = function(.) otu_table(.) %>% as.data.frame() %>% rownames_to_column('feature_id') %>% as_tibble()
get_tax = function(.) tax_table(.) %>% data.frame() %>% rownames_to_column('feature_id') %>% as_tibble()
get_qza = function(filepath){read_qza(filepath)$data %>% as.data.frame() %>% rownames_to_column('SampleID')}
  mutate(SampleID = str_replace(SampleID, '(.*?)-(.*)', '\\2-\\1'),
         SampleID = str_replace_all(SampleID, c('-B73'='-373', '-C322'='-322')))
change_16S_ids_to_match_ITS = . %>% 
  mutate(SampleID = str_replace(SampleID, '(.*?)-(.*)', '\\2-\\1'),
ps = list('16S'= qza_to_phyloseq(features = here('data', '16S', 'table_wo_outliers.qza'),
                          tree=here('data', '16S', 'rooted-tree.qza'),
                          taxonomy=here('data', '16S', 'merged-taxonomy.qza'),
                          metadata=here('data', '16S', 'metadata_filtered.tsv'),
                          tmp='C:/Users/brian.mack/Downloads/tmp') %>% 
            subset_samples(CornVariety != 'dummy' & Timepoint == '2' & TissueType == 'Ovule') %>%
            prune_taxa(taxa_sums(.) > 0, .),
          'ITS' = qza_to_phyloseq(features = here('data', 'ITS', 'table-no-mitochondria-no-chloroplast.qza'),
                          tree=here('data', 'ITS', 'rooted-tree.qza'),
                          taxonomy=here('data', 'ITS', 'merged-taxonomy.qza'),
                          metadata=here('data', 'ITS', 'metadata_merged.tsv'),
                          tmp='C:/Users/brian.mack/Downloads/tmp')  %>% 
            subset_samples(CornVariety  != 'dummy' & Timepoint == '2' & TissueType == 'Ovule') %>%
            prune_taxa(taxa_sums(.) > 0, .)
            )
ps = map(ps, function(.x){
  sample_data(.x) = get_sample_data(.x) %>% 
    rename(TimePoint = Timepoint) %>%
    mutate(TimePoint = str_replace(TimePoint, '^', 'T'),
           condition = str_c(CornVariety, FungalStrain, TissueExtraction, sep='_')) %>%
    rename(Corn_Genotype = CornVariety, Fungal_Treatment = FungalStrain, Tissue_Extraction = TissueExtraction) %>%
    group_by(condition) %>%
    mutate(biological_rep = row_number()) %>%
    ungroup() %>%
    mutate(condition_w_rep = str_c(condition, biological_rep, sep='_')) %>%
    column_to_rownames('SampleID')
  return(.x)})
sample_data(ps$ITS) = get_sample_data(ps$ITS) %>%
  change_its_ids_to_match_16S() %>%
  column_to_rownames('SampleID')
ps %>% imap(~get_counts(.x) %>% 
              left_join(get_tax(.x), by='feature_id') %>%
              rename(all_of(get_sample_data(.x) %>% pull(SampleID, name=condition_w_rep))) %>%
              write_csv(here(str_glue('output/raw_counts_and_taxonomy_{.y}.csv')))
              )

Removed taxa not assigned to a phylum. After removing these taxa, 1 16S samples was removed due to having total counts <= 1500.

ps_phylum_filt = list('16S' = subset_taxa(ps$`16S`, !is.na(Phylum) & 
                        prune_samples(sample_sums(.) >= 1500, .) %>% prune_taxa(taxa_sums(.) > 0, .),
                      'ITS' = subset_taxa(ps$ITS, !is.na(Phylum) & 
                               !Phylum %in% c("", 'uncharacterized', 'unidentified')) %>% 
                        prune_samples(sample_sums(.) >= 1500, .) %>% prune_taxa(taxa_sums(.) > 0, .))
ps_phylum_filt_tax = ps_phylum_filt %>% map(get_tax)
ps_phylum_filt_counts = ps_phylum_filt %>% map(get_counts)
ps_phylum_filt_ra = map(ps_phylum_filt, ~transform_sample_counts(.x, function(x){x / sum(x)}))
ps_phylum_filt
phyloseq-class experiment-level object
otu_table()   OTU Table:          [ 946 taxa and 48 samples ]:
sample_data() Sample Data:        [ 48 samples by 10 sample variables ]:
tax_table()   Taxonomy Table:     [ 946 taxa by 7 taxonomic ranks ]:
phy_tree()    Phylogenetic Tree:  [ 946 tips and 919 internal nodes ]:
taxa are rows
sample_data() Sample Data:        [ 50 samples by 9 sample variables ]:tax_table()   Taxonomy Table:     [ 246 taxa by 7 taxonomic ranks ]:
ps_phylum_filt %>% imap(function(ps_phylum_filt, seq_type){
  ps_phylum_filt %>% get_tax() %>%
    summarize(across(-feature_id, ~sum(!is.na(.x))/ n())) %>%
    round(2) %>%
    pivot_longer(everything(), names_to = 'Taxonomic rank', values_to = seq_type)
  }) %>%
  reduce(full_join, by='Taxonomic rank') %>%
  kbl(format = 'html', caption='Fraction of ASVs classified at each rank') %>%
  kable_classic(full_width = F, html_font = "Times New Roman") 
Fraction of ASVs classified at each rank
Taxonomic rank 16S ITS
Kingdom 1.00 1.00
Phylum 1.00 1.00
Class 1.00 0.99
Order 1.00 0.93
Family 0.99 0.89
Genus 0.91 0.86
Species 0.28 0.73
ps_phylum_filt %>% imap(function(ps_phylum_filt, seq_type){
  ps_phylum_filt %>% sample_sums() %>% enframe(name = 'SampleID', value = 'total_counts') %>%
    left_join(metadata, by='SampleID') %>%
    mutate(seq_type = seq_type)
  }) %>%
  bind_rows() %>%
  ggplot(aes(x=condition, y=total_counts)) +
  geom_boxplot(outlier.shape = NA) +
  ggbeeswarm::geom_quasirandom(alpha = 0.3, width=0.2, groupOnX=TRUE) +
  facet_wrap(~seq_type, ncol=1, scales = 'free') +
  scale_y_continuous(labels = scales::comma) +
  labs(title='Total number of counts for each sample') +
  ggeasy::easy_rotate_x_labels() +
  ggeasy::easy_center_title()




Rarefying to 1569 counts.

ps_phylum_filt_rarefied =  ps_phylum_filt %>% map(
  ~rarefy_even_depth(.x, sample.size = 1569, rngseed=1100 , replace=FALSE) %>%
     prune_taxa(taxa_sums(.) > 0, .))
ps_phylum_filt_rarefied
$`16S`

otu_table()   OTU Table:          [ 579 taxa and 48 samples ]:
sample_data() Sample Data:        [ 48 samples by 10 sample variables ]:




phyloseq-class experiment-level object
sample_data() Sample Data:        [ 50 samples by 9 sample variables ]:
phy_tree()    Phylogenetic Tree:  [ 111 tips and 109 internal nodes ]:taxa are rows







prev = map(ps_phylum_filt_ra,
            function(ps_phylum_filt_ra){
              relative_counts = ps_phylum_filt_ra %>% get_counts()
              tax = ps_phylum_filt_ra %>% get_tax()
              relative_counts %>% 
                reframe(feature_id = feature_id,
                         prevalence = rowSums(.> 0) -1, #subtracted 1 because feature_id column is always counted
                         total_relative_abundance = taxa_sums(ps_phylum_filt_ra), 
                         Phylum = tax$Phylum,
                         Genus = tax$Genus,
prev_plots = prev %>% imap(function(prev, seq_type){
    mutate(prevalence = prevalence / nsamples(ps_phylum_filt[[seq_type]])) %>%
  ggplot(aes(total_relative_abundance, prevalence, color=Phylum, text=glue('Genus: {Genus}<br>Species: {Species}'))) +
    geom_hline(yintercept = 0.05, alpha = 0.5, linetype = 2) + 
    scale_x_log10() + xlab("Total Relative Abundance") + ylab("Prevalence [Fraction Samples]") +
    facet_wrap(~Phylum) +
    theme(plot.title = element_text(hjust = 0.5)) +
    theme(legend.position="none")})
prev_plots$`16S` %>% plotly::ggplotly()
prev_plots$ITS %>% plotly::ggplotly()

Predominant phyla

ps_phyla = map(ps_phylum_filt, 
               function(ps_phylum_filt){
                 ps_phyla = tax_glom(ps_phylum_filt, "Phylum", NArm = TRUE)
                 prevalenceThreshold =  0.05 * nsamples(ps_phyla)
                   get_counts() %>% 
                   summarise(feature_id = feature_id,
                             prevalence = rowSums(.> 0),
                   prune_taxa(., ps_phyla) %>%
                   prune_samples(sample_sums(.) >= 500, .) %>% 
                   prune_taxa(taxa_sums(.) > 0, .)
                 sample_data(ps_phyla) = sample_data(ps_phyla) %>% 
                   as('data.frame') %>%
                   mutate(TissueType = fct_relevel(TissueType, 'Ovule'))
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
ps_phyla_ra = map(ps_phyla, ~transform_sample_counts(.x, function(x){x / sum(x)}))
prev_corn_phyla = map(ps_phyla_ra,
            relative_counts = ps_phyla_ra %>% get_counts()
              tax = ps_phyla_ra %>% get_tax()
              relative_counts %>% 
                pivot_longer(-feature_id, names_to = 'SampleID', values_to = 'counts') %>%
                left_join(metadata, by='SampleID') %>%
                left_join(tax, by='feature_id') %>%
                group_by(Phylum) %>%
                mutate(prevalence_entire_dataset = sum(counts > 0) / n(),
                       mean_relative_abundance_entire_dataset = mean(counts)) %>%
                summarize(prevalence = sum(counts > 0) / n(),
                          prevalence_entire_dataset = first(prevalence_entire_dataset),
                          mean_relative_abundance_entire_dataset = first(mean_relative_abundance_entire_dataset)) %>%
                ungroup()})
prev_corn_phyla$`16S` %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Phylum, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  filter(total >= 0.01) %>%
                                     'Relative abundance B73', 'Relative abundance CML322')) %>%
Phylum Total Relative Abundance Relative abundance B73 Relative abundance CML322
Proteobacteria 0.866 0.829 0.899
Firmicutes 0.065 0.118 0.016
Actinobacteriota 0.038 0.041 0.035
Bacteroidota 0.030 0.010 0.050
prev_corn_phyla$ITS %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Phylum, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  #filter(total >= 0.01) %>%
  arrange(desc(total)) %>%
  kbl(format = 'html', col.names = c('Phylum', 'Total Relative Abundance', 
                                     'Relative abundance B73', 'Relative abundance CML322')) %>%
Phylum Total Relative Abundance Relative abundance B73 Relative abundance CML322
Ascomycota 0.999 0.999 0.999
Basidiomycota 0.001 0.001 0.001




Removed taxa that are present in less than 5% of samples for ASV level dataset. This will be used for differential abundance testing at ASV level.

ps_prevf = map2(ps_phylum_filt, prev,
               function(ps_phylum_filt, prev){
                 keepTaxa = filter(prev, prevalence >= prevalenceThreshold) %>% 
                   pull(feature_id)
                 prune_taxa(keepTaxa, ps_phylum_filt) %>%
                   prune_taxa(taxa_sums(.) > 0, .)})
ps_prevf_ra = map(ps_prevf, ~transform_sample_counts(.x, function(x){x / sum(x)}))
ps_prevf_clr = map(ps_prevf, microbiome::transform, 'clr')
ps_prevf_alr = map(ps_prevf, microbiome::transform, 'alr', shift=1)
ps_prevf
$`16S`
phyloseq-class experiment-level object
otu_table()   OTU Table:          [ 287 taxa and 48 samples ]:
sample_data() Sample Data:        [ 48 samples by 10 sample variables ]:
tax_table()   Taxonomy Table:     [ 287 taxa by 7 taxonomic ranks ]:phy_tree()    Phylogenetic Tree:  [ 287 tips and 278 internal nodes ]:taxa are rows$ITS

otu_table()   OTU Table:          [ 51 taxa and 50 samples ]:sample_data() Sample Data:        [ 50 samples by 9 sample variables ]:
tax_table()   Taxonomy Table:     [ 51 taxa by 7 taxonomic ranks ]:phy_tree()    Phylogenetic Tree:  [ 51 tips and 50 internal nodes ]:taxa are rows




Agglomerated counts at both genus level and species level.

ps_genus = map(ps_phylum_filt, 
               function(ps_phylum_filt){
                 ps_genus = tax_glom(ps_phylum_filt, "Genus", NArm = TRUE)
                 ps_genus = ps_genus %>% 
                   summarise(feature_id = feature_id,
                             prevalence = rowSums(.> 0),
                             TotalAbundance = taxa_sums(ps_genus)) %>%
                   filter(prevalence >= prevalenceThreshold) %>% 
                   prune_taxa(., ps_genus) %>%
                   prune_samples(sample_sums(.) >= 500, .) %>% 
                   prune_taxa(taxa_sums(.) > 0, .)
                 sample_data(ps_genus) = sample_data(ps_genus) %>% 
                   as('data.frame') %>%
                   mutate(TissueType = fct_relevel(TissueType, 'Ovule'))
                 return(ps_genus)})
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
ps_genus_ra = map(ps_genus, ~transform_sample_counts(.x, function(x){x / sum(x)}))
ps_genus_clr = map(ps_genus, microbiome::transform, 'clr')
ps_genus_alr = map(ps_genus, microbiome::transform, 'alr', shift=1)
ps_species = map(ps_phylum_filt, 
               function(ps_phylum_filt){
                 ps_species = tax_glom(ps_phylum_filt, "Species", NArm = TRUE)
                 prevalenceThreshold =  0.05 * nsamples(ps_species)
                 ps_species = ps_species %>% 
                   get_counts() %>% 
                   summarise(feature_id = feature_id,
                   prune_samples(sample_sums(.) >= 500, .) %>% 
                   prune_taxa(taxa_sums(.) > 0, .)
                 sample_data(ps_species) = sample_data(ps_species) %>% 
                   as('data.frame') %>%
                   mutate(TissueType = fct_relevel(TissueType, 'Ovule'))
                 return(ps_species)})
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
ps_species_ra = map(ps_species, ~transform_sample_counts(.x, function(x){x / sum(x)}))
ps_species_clr = map(ps_species, microbiome::transform, 'clr')
ps_species_alr = map(ps_species, microbiome::transform, 'alr', shift=1)

Most prevalent genera

prev_corn_genus = map(ps_genus_ra,
            function(ps_genus_ra){
            relative_counts = ps_genus_ra %>% get_counts()
              tax = ps_genus_ra %>% get_tax()
              relative_counts %>% 
                pivot_longer(-feature_id, names_to = 'SampleID', values_to = 'counts') %>%
                left_join(tax, by='feature_id') %>%
                       mean_relative_abundance_entire_dataset = mean(counts)) %>%
                group_by(Genus, Corn_Genotype) %>%
                summarize(prevalence = sum(counts > 0) / n(),
                          mean_relative_abundance = mean(counts),
                          prevalence_entire_dataset = first(prevalence_entire_dataset),
                          mean_relative_abundance_entire_dataset = first(mean_relative_abundance_entire_dataset)) %>%
                ungroup()})
prev_corn_genus$`16S` %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Genus, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  filter(total >= 0.01) %>%
  arrange(desc(total)) %>%
  kable_classic(full_width = F, html_font = "Times New Roman")
Genus Total Relative Abundance Relative abundance B73 Relative abundance CML322
Pantoea 0.461 0.419 0.500
Klebsiella 0.094 0.024 0.159
Enterobacter 0.051 0.101 0.005
Carnimonas 0.041 0.085 0.000
Burkholderia-Caballeronia-Paraburkholderia 0.030 0.048 0.013
Serratia 0.029 0.033 0.026
Stenotrophomonas 0.029 0.014 0.043
Lactococcus 0.024 0.048 0.003
Sphingobacterium 0.024 0.007 0.039
Achromobacter 0.023 0.008 0.036
Rosenbergiella 0.022 0.047 0.000
Listeria 0.019 0.040 0.000
Allorhizobium-Neorhizobium-Pararhizobium-Rhizobium 0.017 0.009 0.023
Ochrobactrum 0.017 0.013 0.020
Enterococcus 0.010 0.013 0.007
prev_corn_genus$ITS %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Genus, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  #filter(total >= 0.01) %>%
  arrange(desc(total)) %>%
                                     'Relative abundance B73', 'Relative abundance CML322')) %>%
Genus Total Relative Abundance Relative abundance B73 Relative abundance CML322
Aspergillus 0.552 0.497 0.608
Sarocladium 0.252 0.226 0.279
Meyerozyma 0.124 0.148 0.101
Talaromyces 0.040 0.076 0.003
Trichoderma 0.013 0.026 0.001
Penicillium 0.006 0.011 0.001
Curvularia 0.005 0.007 0.003
Alternaria 0.004 0.007 0.002
Ramichloridium 0.001 0.001 0.001
Acremonium 0.000 0.001 0.000
Bipolaris 0.000 0.000 0.000
Candida 0.000 0.000 0.000
Ceriporia 0.000 0.000 0.000
Cladosporium 0.000 0.000 0.000
Cyphellophora 0.000 0.000 0.000
Exserohilum 0.000 0.000 0.000
Fomes 0.000 0.000 0.000
Fusarium 0.000 0.000 0.000
Lecanicillium 0.000 0.000 0.000
Moesziomyces 0.000 0.000 0.000
Myrothecium 0.000 0.001 0.000
Paraconiothyrium 0.000 0.000 0.000
Peniophora 0.000 0.000 0.000
Peziza 0.000 0.001 0.000
Phanerochaete 0.000 0.000 0.000
Phlebia 0.000 0.000 0.000
Pyricularia 0.000 0.000 0.000
Scopuloides 0.000 0.000 0.000
Stereum 0.000 0.001 0.000
Tinctoporellus 0.000 0.000 0.000
Trametes 0.000 0.000 0.000
unidentified 0.000 0.000 0.000

Most prevalent species

prev_corn_species = map(ps_species_ra,
            function(ps_species_ra){
            relative_counts = ps_species_ra %>% get_counts()
              tax = ps_species_ra %>% get_tax()
              relative_counts %>% 
                pivot_longer(-feature_id, names_to = 'SampleID', values_to = 'counts') %>%
                mutate(prevalence_entire_dataset = sum(counts > 0) / n(),
                       mean_relative_abundance_entire_dataset = mean(counts)) %>%
                group_by(Species, Corn_Genotype) %>%
                summarize(prevalence = sum(counts > 0) / n(),
                          mean_relative_abundance = mean(counts),
                          prevalence_entire_dataset = first(prevalence_entire_dataset),
                          mean_relative_abundance_entire_dataset = first(mean_relative_abundance_entire_dataset)) %>%
                ungroup()})
prev_corn_species$`16S` %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Species, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  filter(total >= 0.01) %>%
  arrange(desc(total)) %>%
  kbl(format = 'html', col.names = c('Species', 'Total Relative Abundance', 
                                     'Relative abundance B73', 'Relative abundance CML322')) %>%
  kable_classic(full_width = F, html_font = "Times New Roman")
Species Total Relative Abundance Relative abundance B73 Relative abundance CML322
Pantoea_ananatis 0.193 0.207 0.173
Burkholderia_gladioli 0.152 0.195 0.091
Listeria_grayi 0.070 0.119 0.000
Lactococcus_lactis 0.068 0.077 0.056
Sphingobacterium_siyangense 0.050 0.001 0.120
Lactococcus_garvieae 0.043 0.073 0.000
Sphingobacterium_thalpophilum 0.032 0.000 0.079
Sphingomonas_phyllosphaerae 0.030 0.000 0.073
Acinetobacter_baumannii 0.029 0.000 0.070
Pseudomonas_psychrotolerans 0.026 0.008 0.052
Comamonas_sediminis 0.023 0.000 0.056
Corynebacterium_kroppenstedtii 0.021 0.036 0.000
Flavobacterium_anatoliense 0.019 0.000 0.047
Sphingobacterium_multivorum 0.015 0.012 0.019
Staphylococcus_sciuri 0.015 0.026 0.000
Devosia_riboflavina 0.014 0.000 0.035
uncultured_Tistrella 0.013 0.023 0.000
uncultured_bacterium 0.010 0.014 0.003
prev_corn_species$ITS %>% 
  rename(total = mean_relative_abundance_entire_dataset) %>%
  distinct(Species, Corn_Genotype, mean_relative_abundance, total) %>%
  mutate(mean_relative_abundance= round(mean_relative_abundance, 3),
         total = round(total, 3)) %>%
  pivot_wider(names_from = Corn_Genotype, values_from = mean_relative_abundance) %>%
  filter(total >= 0.01) %>%
  kbl(format = 'html', col.names = c('Species', 'Total Relative Abundance', 
                                     'Relative abundance B73', 'Relative abundance CML322')) %>%
Species Total Relative Abundance Relative abundance B73 Relative abundance CML322
Aspergillus_flavus 0.567 0.525 0.608
Sarocladium_zeae 0.259 0.234 0.284
Meyerozyma_caribbica 0.135 0.168 0.102
Aspergillus_niger 0.011 0.021 0.000
Talaromyces_purpureogenus 0.010 0.019 0.000
reads = list('16S' = read_qza(here('data', '16S', 'rep-seqs-filtered.qza'))$data,
             'ITS' = read_qza(here('data', 'ITS', 'rep-seqs-filtered.qza'))$data)

Below are barplots of relative taxon abundances for 16S sequencing with samples grouped according to similarity using the neatmap method.

## https://github.com/google/palette.js/blob/79a703df344e3b24380ce1a211a2df7f2d90ca22/palette.js#L802
mpn65 = c('#ff0029','#377eb8','#66a61e','#984ea3','#00d2d5','#ff7f00','#af8d00','#7f80cd','#b3e900','#c42e60','#a65628',
         '#f781bf','#8dd3c7','#bebada','#fb8072','#80b1d3','#fdb462','#fccde5','#bc80bd','#ffed6f','#c4eaff','#cf8c00',
         '#1b9e77','#d95f02','#e7298a','#e6ab02','#a6761d','#0097ff','#00d067','#000000','#252525','#525252','#737373',
         '#969696','#bdbdbd','#f43600','#4ba93b','#5779bb','#927acc','#97ee3f','#bf3947','#9f5b00','#f48758','#8caed6',
         '#cbe8ff','#fecddf','#c27eb6','#8cd2ce','#c4b8d9','#f883b0','#a49100','#f48800','#27d0df','#a04a9b')
map(rank_names(ps_genus$`16S`)[2:6], function(tax_rank){
  df = ps_genus$`16S` %>% 
    speedyseq::mutate_sample_data(condition = condition_w_rep) %>%
    transform(transform = "compositional") %>%
    aggregate_rare(level = tax_rank, detection = 0.05, prevalence = 0.05) 
  scale_fill_manual(values=mpn65) +
  theme(axis.text.x=element_text(angle=90,hjust=0, vjust=0.5)) +
  labs(x = "Sample condition",
       y = "Relative abundance",
       title = glue("16S Relative abundance at {tax_rank} level"), 
       fill = tax_rank)
})
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]
NA







The next two sets are done with ITS counts but made the same way as above.

map(rank_names(ps_genus$ITS)[2:6], function(tax_rank){
    speedyseq::mutate_sample_data(condition = condition_w_rep) %>%
    transform(transform = "compositional") %>%
    aggregate_rare(level = tax_rank, detection = 0.05, prevalence = 0.05) 
  p = plot_composition(df, x.label='condition', otu.sort = 'abundance', sample.sort='neatmap') +
  guides(fill = guide_legend(ncol = 1)) +
  scale_fill_manual(values=mpn65) +
  labs(x = "Sample condition",
       y = "Relative abundance",
       title = glue("ITS Relative abundance at {tax_rank} level"), 
  p %>% plotly::ggplotly()
Warning: stress is (nearly) zero: you may have insufficient data
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]
NA
prune_taxa(names(sort(taxa_sums(ps_genus_ra$`16S`),decreasing = TRUE)[1:30]), ps_genus_ra$`16S`) %>%
  speedyseq::plot_heatmap(method = "NMDS", distance = "bray", sample.label = 'condition', taxa.label='Genus') +
        strip.text.x = element_text(size = 16), plot.title = element_text(size=22)) +
  labs(title = '16S Heatmap of top 30 most abundant genera')







prune_taxa(names(sort(taxa_sums(ps_genus_ra$ITS),decreasing = TRUE)[1:30]), ps_genus_ra$ITS) %>%
  speedyseq::plot_heatmap(method = "NMDS", distance = "bray", sample.label = 'condition', taxa.label='Genus') +
        strip.text.x = element_text(size = 16), plot.title = element_text(size=22)) +
  labs(title = 'ITS Heatmap of top 30 most abundant genera')

save.image(here('src/16_and_ITS_import.RData'))
LS0tDQp0aXRsZTogIjE2UyBhbmQgSVRTIGRhdGEgaW1wb3J0Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICBlZGl0b3Jfb3B0aW9uczogDQogICAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KHFpaW1lMlIpDQpsaWJyYXJ5KGdnZWFzeSkNCmxpYnJhcnkocGh5bG9zZXEpDQpsaWJyYXJ5KEJpb3N0cmluZ3MpDQpsaWJyYXJ5KGdnc2lnbmlmKQ0KbGlicmFyeShnZ2Vhc3kpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShwYXRjaHdvcmspDQpsaWJyYXJ5KERFU2VxMikNCmxpYnJhcnkoQUxERXgyKQ0KbGlicmFyeShtaWNyb2Jpb21lKSANCmxpYnJhcnkodmVnYW4pDQpsaWJyYXJ5KEFOQ09NQkMpDQpsaWJyYXJ5KGdsdWUpDQpsaWJyYXJ5KGdnc3RhdHNwbG90KQ0KbGlicmFyeShiZWVzd2FybSkNCmxpYnJhcnkobXNhKQ0KbGlicmFyeShoZXJlKQ0KbGlicmFyeShnZ3RleHQpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KHRpZHlIZWF0bWFwKQ0KbGlicmFyeShTcGllY0Vhc2kpDQpsaWJyYXJ5KE5ldENvTWkpDQpsaWJyYXJ5KGlncmFwaCkNCmxpYnJhcnkodGlkeWdyYXBoKQ0KbGlicmFyeShnZ3JhcGgpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcucmV0aW5hID0gMSwgZHBpPTQ1MCkNCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybT1GKQ0KdGhlbWVfc2V0KHRoZW1lX2J3KCkpDQpzZXNzaW9uSW5mbygpICU+JQ0KICBjYXB0dXJlLm91dHB1dChzZXNzaW9uSW5mbygpKSAlPiUNCiAgd3JpdGVfbGluZXMoaGVyZSgnb3V0cHV0L3Nlc3Npb25faW5mby50eHQnKSkNCmBgYA0KDQpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQptZXRhZGF0YSA9IHJlYWRfdHN2KGhlcmUoJ2RhdGEnLCAnbWV0YWRhdGFfbWVyZ2VkLnRzdicpLCBjb2xfdHlwZXMgPSBjb2xzKCkpICU+JQ0KICByZW5hbWUoVGltZVBvaW50ID0gVGltZXBvaW50KSAlPiUNCiAgbXV0YXRlKFRpbWVQb2ludCA9IHN0cl9yZXBsYWNlKFRpbWVQb2ludCwgJ14nLCAnVCcpLA0KICAgICAgICAgY29uZGl0aW9uID0gc3RyX2MoQ29yblZhcmlldHksIEZ1bmdhbFN0cmFpbiwgVGlzc3VlRXh0cmFjdGlvbiwgc2VwPSdfJykpICU+JQ0KICByZW5hbWUoQ29ybl9HZW5vdHlwZSA9IENvcm5WYXJpZXR5LCBGdW5nYWxfVHJlYXRtZW50ID0gRnVuZ2FsU3RyYWluLCBUaXNzdWVfRXh0cmFjdGlvbiA9IFRpc3N1ZUV4dHJhY3Rpb24pDQpgYGANCg0KYGBge3J9DQpnZXRfY291bnRzID0gZnVuY3Rpb24oLikgb3R1X3RhYmxlKC4pICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbignZmVhdHVyZV9pZCcpICU+JSBhc190aWJibGUoKQ0KZ2V0X3RheCA9IGZ1bmN0aW9uKC4pIHRheF90YWJsZSguKSAlPiUgZGF0YS5mcmFtZSgpICU+JSByb3duYW1lc190b19jb2x1bW4oJ2ZlYXR1cmVfaWQnKSAlPiUgYXNfdGliYmxlKCkNCmdldF9xemEgPSBmdW5jdGlvbihmaWxlcGF0aCl7cmVhZF9xemEoZmlsZXBhdGgpJGRhdGEgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCdTYW1wbGVJRCcpfQ0KZ2V0X3NhbXBsZV9kYXRhID0gZnVuY3Rpb24oLikgZGF0YS5mcmFtZShzYW1wbGVfZGF0YSguKSkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbignU2FtcGxlSUQnKSAlPiUgYXNfdGliYmxlKCkNCmNoYW5nZV9pdHNfaWRzX3RvX21hdGNoXzE2UyA9IC4gJT4lIA0KICBtdXRhdGUoU2FtcGxlSUQgPSBzdHJfcmVwbGFjZShTYW1wbGVJRCwgJyguKj8pLSguKiknLCAnXFwyLVxcMScpLA0KICAgICAgICAgU2FtcGxlSUQgPSBzdHJfcmVwbGFjZV9hbGwoU2FtcGxlSUQsIGMoJy1CNzMnPSctMzczJywgJy1DMzIyJz0nLTMyMicpKSkNCmNoYW5nZV8xNlNfaWRzX3RvX21hdGNoX0lUUyA9IC4gJT4lIA0KICBtdXRhdGUoU2FtcGxlSUQgPSBzdHJfcmVwbGFjZShTYW1wbGVJRCwgJyguKj8pLSguKiknLCAnXFwyLVxcMScpLA0KICAgICAgICAgU2FtcGxlSUQgPSBzdHJfcmVwbGFjZV9hbGwoU2FtcGxlSUQsIGMoJy0zNzMnPSctQjczJywgJy0zMjInPSctQzMyMicpKSkNCmBgYA0KDQpgYGB7cn0NCnBzID0gbGlzdCgnMTZTJz0gcXphX3RvX3BoeWxvc2VxKGZlYXR1cmVzID0gaGVyZSgnZGF0YScsICcxNlMnLCAndGFibGVfd29fb3V0bGllcnMucXphJyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRyZWU9aGVyZSgnZGF0YScsICcxNlMnLCAncm9vdGVkLXRyZWUucXphJyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRheG9ub215PWhlcmUoJ2RhdGEnLCAnMTZTJywgJ21lcmdlZC10YXhvbm9teS5xemEnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE9aGVyZSgnZGF0YScsICcxNlMnLCAnbWV0YWRhdGFfZmlsdGVyZWQudHN2JyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRtcD0nQzovVXNlcnMvYnJpYW4ubWFjay9Eb3dubG9hZHMvdG1wJykgJT4lIA0KICAgICAgICAgICAgc3Vic2V0X3NhbXBsZXMoQ29yblZhcmlldHkgIT0gJ2R1bW15JyAmIFRpbWVwb2ludCA9PSAnMicgJiBUaXNzdWVUeXBlID09ICdPdnVsZScpICU+JQ0KICAgICAgICAgICAgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKSwNCiAgICAgICAgICAnSVRTJyA9IHF6YV90b19waHlsb3NlcShmZWF0dXJlcyA9IGhlcmUoJ2RhdGEnLCAnSVRTJywgJ3RhYmxlLW5vLW1pdG9jaG9uZHJpYS1uby1jaGxvcm9wbGFzdC5xemEnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJlZT1oZXJlKCdkYXRhJywgJ0lUUycsICdyb290ZWQtdHJlZS5xemEnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGF4b25vbXk9aGVyZSgnZGF0YScsICdJVFMnLCAnbWVyZ2VkLXRheG9ub215LnF6YScpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YT1oZXJlKCdkYXRhJywgJ0lUUycsICdtZXRhZGF0YV9tZXJnZWQudHN2JyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRtcD0nQzovVXNlcnMvYnJpYW4ubWFjay9Eb3dubG9hZHMvdG1wJykgICU+JSANCiAgICAgICAgICAgIHN1YnNldF9zYW1wbGVzKENvcm5WYXJpZXR5ICAhPSAnZHVtbXknICYgVGltZXBvaW50ID09ICcyJyAmIFRpc3N1ZVR5cGUgPT0gJ092dWxlJykgJT4lDQogICAgICAgICAgICBwcnVuZV90YXhhKHRheGFfc3VtcyguKSA+IDAsIC4pDQogICAgICAgICAgICApDQpwcyA9IG1hcChwcywgZnVuY3Rpb24oLngpew0KICBzYW1wbGVfZGF0YSgueCkgPSBnZXRfc2FtcGxlX2RhdGEoLngpICU+JSANCiAgICByZW5hbWUoVGltZVBvaW50ID0gVGltZXBvaW50KSAlPiUNCiAgICBtdXRhdGUoVGltZVBvaW50ID0gc3RyX3JlcGxhY2UoVGltZVBvaW50LCAnXicsICdUJyksDQogICAgICAgICAgIGNvbmRpdGlvbiA9IHN0cl9jKENvcm5WYXJpZXR5LCBGdW5nYWxTdHJhaW4sIFRpc3N1ZUV4dHJhY3Rpb24sIHNlcD0nXycpKSAlPiUNCiAgICByZW5hbWUoQ29ybl9HZW5vdHlwZSA9IENvcm5WYXJpZXR5LCBGdW5nYWxfVHJlYXRtZW50ID0gRnVuZ2FsU3RyYWluLCBUaXNzdWVfRXh0cmFjdGlvbiA9IFRpc3N1ZUV4dHJhY3Rpb24pICU+JQ0KICAgIGdyb3VwX2J5KGNvbmRpdGlvbikgJT4lDQogICAgbXV0YXRlKGJpb2xvZ2ljYWxfcmVwID0gcm93X251bWJlcigpKSAlPiUNCiAgICB1bmdyb3VwKCkgJT4lDQogICAgbXV0YXRlKGNvbmRpdGlvbl93X3JlcCA9IHN0cl9jKGNvbmRpdGlvbiwgYmlvbG9naWNhbF9yZXAsIHNlcD0nXycpKSAlPiUNCiAgICBjb2x1bW5fdG9fcm93bmFtZXMoJ1NhbXBsZUlEJykNCiAgcmV0dXJuKC54KX0pDQpzYW1wbGVfZGF0YShwcyRJVFMpID0gZ2V0X3NhbXBsZV9kYXRhKHBzJElUUykgJT4lDQogIGNoYW5nZV9pdHNfaWRzX3RvX21hdGNoXzE2UygpICU+JQ0KICBjb2x1bW5fdG9fcm93bmFtZXMoJ1NhbXBsZUlEJykNCnBzICU+JSBpbWFwKH5nZXRfY291bnRzKC54KSAlPiUgDQogICAgICAgICAgICAgIGxlZnRfam9pbihnZXRfdGF4KC54KSwgYnk9J2ZlYXR1cmVfaWQnKSAlPiUNCiAgICAgICAgICAgICAgcmVuYW1lKGFsbF9vZihnZXRfc2FtcGxlX2RhdGEoLngpICU+JSBwdWxsKFNhbXBsZUlELCBuYW1lPWNvbmRpdGlvbl93X3JlcCkpKSAlPiUNCiAgICAgICAgICAgICAgd3JpdGVfY3N2KGhlcmUoc3RyX2dsdWUoJ291dHB1dC9yYXdfY291bnRzX2FuZF90YXhvbm9teV97Lnl9LmNzdicpKSkNCiAgICAgICAgICAgICAgKQ0KYGBgDQoNClJlbW92ZWQgdGF4YSBub3QgYXNzaWduZWQgdG8gYSBwaHlsdW0uIEFmdGVyIHJlbW92aW5nIHRoZXNlIHRheGEsIDEgMTZTIHNhbXBsZXMgd2FzIHJlbW92ZWQgZHVlIHRvIGhhdmluZyB0b3RhbCBjb3VudHMgPD0gMTUwMC4NCg0KYGBge3J9DQpwc19waHlsdW1fZmlsdCA9IGxpc3QoJzE2UycgPSBzdWJzZXRfdGF4YShwcyRgMTZTYCwgIWlzLm5hKFBoeWx1bSkgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIVBoeWx1bSAlaW4lIGMoJycsICd1bmNoYXJhY3Rlcml6ZWQnLCAndW5pZGVudGlmaWVkJykgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIUtpbmdkb20gJWluJSBjKCdkX19FdWthcnlvdGEnKSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgcHJ1bmVfc2FtcGxlcyhzYW1wbGVfc3VtcyguKSA+PSAxNTAwLCAuKSAlPiUgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKSwNCiAgICAgICAgICAgICAgICAgICAgICAnSVRTJyA9IHN1YnNldF90YXhhKHBzJElUUywgIWlzLm5hKFBoeWx1bSkgJiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhUGh5bHVtICVpbiUgYygiIiwgJ3VuY2hhcmFjdGVyaXplZCcsICd1bmlkZW50aWZpZWQnKSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgcHJ1bmVfc2FtcGxlcyhzYW1wbGVfc3VtcyguKSA+PSAxNTAwLCAuKSAlPiUgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKSkNCnBzX3BoeWx1bV9maWx0X3RheCA9IHBzX3BoeWx1bV9maWx0ICU+JSBtYXAoZ2V0X3RheCkNCnBzX3BoeWx1bV9maWx0X2NvdW50cyA9IHBzX3BoeWx1bV9maWx0ICU+JSBtYXAoZ2V0X2NvdW50cykNCnBzX3BoeWx1bV9maWx0X3JhID0gbWFwKHBzX3BoeWx1bV9maWx0LCB+dHJhbnNmb3JtX3NhbXBsZV9jb3VudHMoLngsIGZ1bmN0aW9uKHgpe3ggLyBzdW0oeCl9KSkNCnBzX3BoeWx1bV9maWx0DQpgYGANCmBgYHtyfQ0KcHNfcGh5bHVtX2ZpbHQgJT4lIGltYXAoZnVuY3Rpb24ocHNfcGh5bHVtX2ZpbHQsIHNlcV90eXBlKXsNCiAgcHNfcGh5bHVtX2ZpbHQgJT4lIGdldF90YXgoKSAlPiUNCiAgICBzdW1tYXJpemUoYWNyb3NzKC1mZWF0dXJlX2lkLCB+c3VtKCFpcy5uYSgueCkpLyBuKCkpKSAlPiUNCiAgICByb3VuZCgyKSAlPiUNCiAgICBwaXZvdF9sb25nZXIoZXZlcnl0aGluZygpLCBuYW1lc190byA9ICdUYXhvbm9taWMgcmFuaycsIHZhbHVlc190byA9IHNlcV90eXBlKQ0KICB9KSAlPiUNCiAgcmVkdWNlKGZ1bGxfam9pbiwgYnk9J1RheG9ub21pYyByYW5rJykgJT4lDQogIGtibChmb3JtYXQgPSAnaHRtbCcsIGNhcHRpb249J0ZyYWN0aW9uIG9mIEFTVnMgY2xhc3NpZmllZCBhdCBlYWNoIHJhbmsnKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIlRpbWVzIE5ldyBSb21hbiIpIA0KYGBgDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTZ9DQpwc19waHlsdW1fZmlsdCAlPiUgaW1hcChmdW5jdGlvbihwc19waHlsdW1fZmlsdCwgc2VxX3R5cGUpew0KICBwc19waHlsdW1fZmlsdCAlPiUgc2FtcGxlX3N1bXMoKSAlPiUgZW5mcmFtZShuYW1lID0gJ1NhbXBsZUlEJywgdmFsdWUgPSAndG90YWxfY291bnRzJykgJT4lDQogICAgbGVmdF9qb2luKG1ldGFkYXRhLCBieT0nU2FtcGxlSUQnKSAlPiUNCiAgICBtdXRhdGUoc2VxX3R5cGUgPSBzZXFfdHlwZSkNCiAgfSkgJT4lDQogIGJpbmRfcm93cygpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9Y29uZGl0aW9uLCB5PXRvdGFsX2NvdW50cykpICsNCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKw0KICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKGFscGhhID0gMC4zLCB3aWR0aD0wLjIsIGdyb3VwT25YPVRSVUUpICsNCiAgZmFjZXRfd3JhcCh+c2VxX3R5cGUsIG5jb2w9MSwgc2NhbGVzID0gJ2ZyZWUnKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArDQogIGxhYnModGl0bGU9J1RvdGFsIG51bWJlciBvZiBjb3VudHMgZm9yIGVhY2ggc2FtcGxlJykgKw0KICBnZ2Vhc3k6OmVhc3lfcm90YXRlX3hfbGFiZWxzKCkgKw0KICBnZ2Vhc3k6OmVhc3lfY2VudGVyX3RpdGxlKCkNCmBgYA0KDQo8YnI+PGJyPjxicj4NCg0KUmFyZWZ5aW5nIHRvIDE1NjkgY291bnRzLg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnBzX3BoeWx1bV9maWx0X3JhcmVmaWVkID0gIHBzX3BoeWx1bV9maWx0ICU+JSBtYXAoDQogIH5yYXJlZnlfZXZlbl9kZXB0aCgueCwgc2FtcGxlLnNpemUgPSAxNTY5LCBybmdzZWVkPTExMDAgLCByZXBsYWNlPUZBTFNFKSAlPiUNCiAgICAgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKSkNCnBzX3BoeWx1bV9maWx0X3JhcmVmaWVkDQpgYGANCg0KPGJyPjxicj48YnI+PGJyPjxicj48YnI+DQoNCmBgYHtyLCBmaWcud2lkdGg9MTJ9DQpwcmV2ID0gbWFwKHBzX3BoeWx1bV9maWx0X3JhLA0KICAgICAgICAgICAgZnVuY3Rpb24ocHNfcGh5bHVtX2ZpbHRfcmEpew0KICAgICAgICAgICAgICByZWxhdGl2ZV9jb3VudHMgPSBwc19waHlsdW1fZmlsdF9yYSAlPiUgZ2V0X2NvdW50cygpDQogICAgICAgICAgICAgIHRheCA9IHBzX3BoeWx1bV9maWx0X3JhICU+JSBnZXRfdGF4KCkNCiAgICAgICAgICAgICAgcmVsYXRpdmVfY291bnRzICU+JSANCiAgICAgICAgICAgICAgICByZWZyYW1lKGZlYXR1cmVfaWQgPSBmZWF0dXJlX2lkLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHByZXZhbGVuY2UgPSByb3dTdW1zKC4+IDApIC0xLCAjc3VidHJhY3RlZCAxIGJlY2F1c2UgZmVhdHVyZV9pZCBjb2x1bW4gaXMgYWx3YXlzIGNvdW50ZWQNCiAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9yZWxhdGl2ZV9hYnVuZGFuY2UgPSB0YXhhX3N1bXMocHNfcGh5bHVtX2ZpbHRfcmEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBQaHlsdW0gPSB0YXgkUGh5bHVtLA0KICAgICAgICAgICAgICAgICAgICAgICAgIEdlbnVzID0gdGF4JEdlbnVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgIFNwZWNpZXMgPSB0YXgkU3BlY2llcyl9KQ0KcHJldl9wbG90cyA9IHByZXYgJT4lIGltYXAoZnVuY3Rpb24ocHJldiwgc2VxX3R5cGUpew0KICBwcmV2ICU+JSANCiAgICBtdXRhdGUocHJldmFsZW5jZSA9IHByZXZhbGVuY2UgLyBuc2FtcGxlcyhwc19waHlsdW1fZmlsdFtbc2VxX3R5cGVdXSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHRvdGFsX3JlbGF0aXZlX2FidW5kYW5jZSwgcHJldmFsZW5jZSwgY29sb3I9UGh5bHVtLCB0ZXh0PWdsdWUoJ0dlbnVzOiB7R2VudXN9PGJyPlNwZWNpZXM6IHtTcGVjaWVzfScpKSkgKw0KICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMDUsIGFscGhhID0gMC41LCBsaW5ldHlwZSA9IDIpICsgDQogICAgZ2VvbV9wb2ludChzaXplID0gMiwgYWxwaGEgPSAwLjYpICsNCiAgICBzY2FsZV94X2xvZzEwKCkgKyB4bGFiKCJUb3RhbCBSZWxhdGl2ZSBBYnVuZGFuY2UiKSArIHlsYWIoIlByZXZhbGVuY2UgW0ZyYWN0aW9uIFNhbXBsZXNdIikgKw0KICAgIGZhY2V0X3dyYXAoflBoeWx1bSkgKw0KICAgIGxhYnModGl0bGUgPSBnbHVlKCd7c2VxX3R5cGV9IEFTViBQcmV2YWxlbmNlJykpICsNCiAgICB0aGVtZV9ncmF5KCkgKw0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIil9KQ0KYGBgDQoNCmBgYHtyLCBvdXQud2lkdGg9MTJ9DQpwcmV2X3Bsb3RzJGAxNlNgICU+JSBwbG90bHk6OmdncGxvdGx5KCkNCmBgYA0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD00fQ0KcHJldl9wbG90cyRJVFMgJT4lIHBsb3RseTo6Z2dwbG90bHkoKQ0KYGBgDQpQcmVkb21pbmFudCBwaHlsYQ0KYGBge3J9DQpwc19waHlsYSA9IG1hcChwc19waHlsdW1fZmlsdCwgDQogICAgICAgICAgICAgICBmdW5jdGlvbihwc19waHlsdW1fZmlsdCl7DQogICAgICAgICAgICAgICAgIHBzX3BoeWxhID0gdGF4X2dsb20ocHNfcGh5bHVtX2ZpbHQsICJQaHlsdW0iLCBOQXJtID0gVFJVRSkNCiAgICAgICAgICAgICAgICAgcHJldmFsZW5jZVRocmVzaG9sZCA9ICAwLjA1ICogbnNhbXBsZXMocHNfcGh5bGEpDQogICAgICAgICAgICAgICAgIHBzX3BoeWxhID0gcHNfcGh5bGEgJT4lIA0KICAgICAgICAgICAgICAgICAgIGdldF9jb3VudHMoKSAlPiUgDQogICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKGZlYXR1cmVfaWQgPSBmZWF0dXJlX2lkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2YWxlbmNlID0gcm93U3VtcyguPiAwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVG90YWxBYnVuZGFuY2UgPSB0YXhhX3N1bXMocHNfcGh5bGEpKSAlPiUNCiAgICAgICAgICAgICAgICAgICBmaWx0ZXIocHJldmFsZW5jZSA+PSBwcmV2YWxlbmNlVGhyZXNob2xkKSAlPiUgDQogICAgICAgICAgICAgICAgICAgcHVsbChmZWF0dXJlX2lkKSAlPiUNCiAgICAgICAgICAgICAgICAgICBwcnVuZV90YXhhKC4sIHBzX3BoeWxhKSAlPiUNCiAgICAgICAgICAgICAgICAgICBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKC4pID49IDUwMCwgLikgJT4lIA0KICAgICAgICAgICAgICAgICAgIHBydW5lX3RheGEodGF4YV9zdW1zKC4pID4gMCwgLikNCiAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfcGh5bGEpID0gc2FtcGxlX2RhdGEocHNfcGh5bGEpICU+JSANCiAgICAgICAgICAgICAgICAgICBhcygnZGF0YS5mcmFtZScpICU+JQ0KICAgICAgICAgICAgICAgICAgIG11dGF0ZShUaXNzdWVUeXBlID0gZmN0X3JlbGV2ZWwoVGlzc3VlVHlwZSwgJ092dWxlJykpDQogICAgICAgICAgICAgICAgIHJldHVybihwc19waHlsYSl9KQ0KcHNfcGh5bGFfcmEgPSBtYXAocHNfcGh5bGEsIH50cmFuc2Zvcm1fc2FtcGxlX2NvdW50cygueCwgZnVuY3Rpb24oeCl7eCAvIHN1bSh4KX0pKQ0KcHJldl9jb3JuX3BoeWxhID0gbWFwKHBzX3BoeWxhX3JhLA0KICAgICAgICAgICAgZnVuY3Rpb24ocHNfcGh5bGFfcmEpew0KICAgICAgICAgICAgcmVsYXRpdmVfY291bnRzID0gcHNfcGh5bGFfcmEgJT4lIGdldF9jb3VudHMoKQ0KICAgICAgICAgICAgICB0YXggPSBwc19waHlsYV9yYSAlPiUgZ2V0X3RheCgpDQogICAgICAgICAgICAgIHJlbGF0aXZlX2NvdW50cyAlPiUgDQogICAgICAgICAgICAgICAgcGl2b3RfbG9uZ2VyKC1mZWF0dXJlX2lkLCBuYW1lc190byA9ICdTYW1wbGVJRCcsIHZhbHVlc190byA9ICdjb3VudHMnKSAlPiUNCiAgICAgICAgICAgICAgICBsZWZ0X2pvaW4obWV0YWRhdGEsIGJ5PSdTYW1wbGVJRCcpICU+JQ0KICAgICAgICAgICAgICAgIGxlZnRfam9pbih0YXgsIGJ5PSdmZWF0dXJlX2lkJykgJT4lDQogICAgICAgICAgICAgICAgZ3JvdXBfYnkoUGh5bHVtKSAlPiUNCiAgICAgICAgICAgICAgICBtdXRhdGUocHJldmFsZW5jZV9lbnRpcmVfZGF0YXNldCA9IHN1bShjb3VudHMgPiAwKSAvIG4oKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfZW50aXJlX2RhdGFzZXQgPSBtZWFuKGNvdW50cykpICU+JQ0KICAgICAgICAgICAgICAgIGdyb3VwX2J5KFBoeWx1bSwgQ29ybl9HZW5vdHlwZSkgJT4lDQogICAgICAgICAgICAgICAgc3VtbWFyaXplKHByZXZhbGVuY2UgPSBzdW0oY291bnRzID4gMCkgLyBuKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlID0gbWVhbihjb3VudHMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2YWxlbmNlX2VudGlyZV9kYXRhc2V0ID0gZmlyc3QocHJldmFsZW5jZV9lbnRpcmVfZGF0YXNldCksDQogICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0ID0gZmlyc3QobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfZW50aXJlX2RhdGFzZXQpKSAlPiUNCiAgICAgICAgICAgICAgICB1bmdyb3VwKCl9KQ0KcHJldl9jb3JuX3BoeWxhJGAxNlNgICU+JSANCiAgcmVuYW1lKHRvdGFsID0gbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfZW50aXJlX2RhdGFzZXQpICU+JQ0KICBkaXN0aW5jdChQaHlsdW0sIENvcm5fR2Vub3R5cGUsIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCB0b3RhbCkgJT4lDQogIG11dGF0ZShtZWFuX3JlbGF0aXZlX2FidW5kYW5jZT0gcm91bmQobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIDMpLA0KICAgICAgICAgdG90YWwgPSByb3VuZCh0b3RhbCwgMykpICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ29ybl9HZW5vdHlwZSwgdmFsdWVzX2Zyb20gPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSkgJT4lDQogIGZpbHRlcih0b3RhbCA+PSAwLjAxKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lDQogIGtibChmb3JtYXQgPSAnaHRtbCcsIGNvbC5uYW1lcyA9IGMoJ1BoeWx1bScsICdUb3RhbCBSZWxhdGl2ZSBBYnVuZGFuY2UnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmVsYXRpdmUgYWJ1bmRhbmNlIEI3MycsICdSZWxhdGl2ZSBhYnVuZGFuY2UgQ01MMzIyJykpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiVGltZXMgTmV3IFJvbWFuIikNCnByZXZfY29ybl9waHlsYSRJVFMgJT4lIA0KICByZW5hbWUodG90YWwgPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCkgJT4lDQogIGRpc3RpbmN0KFBoeWx1bSwgQ29ybl9HZW5vdHlwZSwgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIHRvdGFsKSAlPiUNCiAgbXV0YXRlKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlPSByb3VuZChtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSwgMyksDQogICAgICAgICB0b3RhbCA9IHJvdW5kKHRvdGFsLCAzKSkgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBDb3JuX0dlbm90eXBlLCB2YWx1ZXNfZnJvbSA9IG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlKSAlPiUNCiAgI2ZpbHRlcih0b3RhbCA+PSAwLjAxKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lDQogIGtibChmb3JtYXQgPSAnaHRtbCcsIGNvbC5uYW1lcyA9IGMoJ1BoeWx1bScsICdUb3RhbCBSZWxhdGl2ZSBBYnVuZGFuY2UnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmVsYXRpdmUgYWJ1bmRhbmNlIEI3MycsICdSZWxhdGl2ZSBhYnVuZGFuY2UgQ01MMzIyJykpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiVGltZXMgTmV3IFJvbWFuIikNCmBgYA0KPGJyPjxicj48YnI+IFJlbW92ZWQgdGF4YSB0aGF0IGFyZSBwcmVzZW50IGluIGxlc3MgdGhhbiA1JSBvZiBzYW1wbGVzIGZvciBBU1YgbGV2ZWwgZGF0YXNldC4gVGhpcyB3aWxsIGJlIHVzZWQgZm9yIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UgdGVzdGluZyBhdCBBU1YgbGV2ZWwuDQpgYGB7cn0NCnBzX3ByZXZmID0gbWFwMihwc19waHlsdW1fZmlsdCwgcHJldiwNCiAgICAgICAgICAgICAgIGZ1bmN0aW9uKHBzX3BoeWx1bV9maWx0LCBwcmV2KXsNCiAgICAgICAgICAgICAgICAgcHJldmFsZW5jZVRocmVzaG9sZCA9ICAwLjA1ICogbnNhbXBsZXMocHNfcGh5bHVtX2ZpbHQpDQogICAgICAgICAgICAgICAgIGtlZXBUYXhhID0gZmlsdGVyKHByZXYsIHByZXZhbGVuY2UgPj0gcHJldmFsZW5jZVRocmVzaG9sZCkgJT4lIA0KICAgICAgICAgICAgICAgICAgIHB1bGwoZmVhdHVyZV9pZCkNCiAgICAgICAgICAgICAgICAgcHJ1bmVfdGF4YShrZWVwVGF4YSwgcHNfcGh5bHVtX2ZpbHQpICU+JQ0KICAgICAgICAgICAgICAgICAgIHBydW5lX3NhbXBsZXMoc2FtcGxlX3N1bXMoLikgPj0gNTAwLCAuKSAlPiUgDQogICAgICAgICAgICAgICAgICAgcHJ1bmVfdGF4YSh0YXhhX3N1bXMoLikgPiAwLCAuKX0pDQpwc19wcmV2Zl9yYSA9IG1hcChwc19wcmV2ZiwgfnRyYW5zZm9ybV9zYW1wbGVfY291bnRzKC54LCBmdW5jdGlvbih4KXt4IC8gc3VtKHgpfSkpDQpwc19wcmV2Zl9jbHIgPSBtYXAocHNfcHJldmYsIG1pY3JvYmlvbWU6OnRyYW5zZm9ybSwgJ2NscicpDQpwc19wcmV2Zl9hbHIgPSBtYXAocHNfcHJldmYsIG1pY3JvYmlvbWU6OnRyYW5zZm9ybSwgJ2FscicsIHNoaWZ0PTEpDQpwc19wcmV2Zg0KYGBgDQoNCjxicj48YnI+PGJyPiBBZ2dsb21lcmF0ZWQgY291bnRzIGF0IGJvdGggZ2VudXMgbGV2ZWwgYW5kIHNwZWNpZXMgbGV2ZWwuDQoNCmBgYHtyfQ0KcHNfZ2VudXMgPSBtYXAocHNfcGh5bHVtX2ZpbHQsIA0KICAgICAgICAgICAgICAgZnVuY3Rpb24ocHNfcGh5bHVtX2ZpbHQpew0KICAgICAgICAgICAgICAgICBwc19nZW51cyA9IHRheF9nbG9tKHBzX3BoeWx1bV9maWx0LCAiR2VudXMiLCBOQXJtID0gVFJVRSkNCiAgICAgICAgICAgICAgICAgcHJldmFsZW5jZVRocmVzaG9sZCA9ICAwLjA1ICogbnNhbXBsZXMocHNfZ2VudXMpDQogICAgICAgICAgICAgICAgIHBzX2dlbnVzID0gcHNfZ2VudXMgJT4lIA0KICAgICAgICAgICAgICAgICAgIGdldF9jb3VudHMoKSAlPiUgDQogICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKGZlYXR1cmVfaWQgPSBmZWF0dXJlX2lkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2YWxlbmNlID0gcm93U3VtcyguPiAwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVG90YWxBYnVuZGFuY2UgPSB0YXhhX3N1bXMocHNfZ2VudXMpKSAlPiUNCiAgICAgICAgICAgICAgICAgICBmaWx0ZXIocHJldmFsZW5jZSA+PSBwcmV2YWxlbmNlVGhyZXNob2xkKSAlPiUgDQogICAgICAgICAgICAgICAgICAgcHVsbChmZWF0dXJlX2lkKSAlPiUNCiAgICAgICAgICAgICAgICAgICBwcnVuZV90YXhhKC4sIHBzX2dlbnVzKSAlPiUNCiAgICAgICAgICAgICAgICAgICBwcnVuZV9zYW1wbGVzKHNhbXBsZV9zdW1zKC4pID49IDUwMCwgLikgJT4lIA0KICAgICAgICAgICAgICAgICAgIHBydW5lX3RheGEodGF4YV9zdW1zKC4pID4gMCwgLikNCiAgICAgICAgICAgICAgICAgc2FtcGxlX2RhdGEocHNfZ2VudXMpID0gc2FtcGxlX2RhdGEocHNfZ2VudXMpICU+JSANCiAgICAgICAgICAgICAgICAgICBhcygnZGF0YS5mcmFtZScpICU+JQ0KICAgICAgICAgICAgICAgICAgIG11dGF0ZShUaXNzdWVUeXBlID0gZmN0X3JlbGV2ZWwoVGlzc3VlVHlwZSwgJ092dWxlJykpDQogICAgICAgICAgICAgICAgIHJldHVybihwc19nZW51cyl9KQ0KcHNfZ2VudXNfcmEgPSBtYXAocHNfZ2VudXMsIH50cmFuc2Zvcm1fc2FtcGxlX2NvdW50cygueCwgZnVuY3Rpb24oeCl7eCAvIHN1bSh4KX0pKQ0KcHNfZ2VudXNfY2xyID0gbWFwKHBzX2dlbnVzLCBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0sICdjbHInKQ0KcHNfZ2VudXNfYWxyID0gbWFwKHBzX2dlbnVzLCBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0sICdhbHInLCBzaGlmdD0xKQ0KcHNfc3BlY2llcyA9IG1hcChwc19waHlsdW1fZmlsdCwgDQogICAgICAgICAgICAgICBmdW5jdGlvbihwc19waHlsdW1fZmlsdCl7DQogICAgICAgICAgICAgICAgIHBzX3NwZWNpZXMgPSB0YXhfZ2xvbShwc19waHlsdW1fZmlsdCwgIlNwZWNpZXMiLCBOQXJtID0gVFJVRSkNCiAgICAgICAgICAgICAgICAgcHJldmFsZW5jZVRocmVzaG9sZCA9ICAwLjA1ICogbnNhbXBsZXMocHNfc3BlY2llcykNCiAgICAgICAgICAgICAgICAgcHNfc3BlY2llcyA9IHBzX3NwZWNpZXMgJT4lIA0KICAgICAgICAgICAgICAgICAgIGdldF9jb3VudHMoKSAlPiUgDQogICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKGZlYXR1cmVfaWQgPSBmZWF0dXJlX2lkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2YWxlbmNlID0gcm93U3VtcyguPiAwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVG90YWxBYnVuZGFuY2UgPSB0YXhhX3N1bXMocHNfc3BlY2llcykpICU+JQ0KICAgICAgICAgICAgICAgICAgIGZpbHRlcihwcmV2YWxlbmNlID49IHByZXZhbGVuY2VUaHJlc2hvbGQpICU+JSANCiAgICAgICAgICAgICAgICAgICBwdWxsKGZlYXR1cmVfaWQpICU+JQ0KICAgICAgICAgICAgICAgICAgIHBydW5lX3RheGEoLiwgcHNfc3BlY2llcykgJT4lDQogICAgICAgICAgICAgICAgICAgcHJ1bmVfc2FtcGxlcyhzYW1wbGVfc3VtcyguKSA+PSA1MDAsIC4pICU+JSANCiAgICAgICAgICAgICAgICAgICBwcnVuZV90YXhhKHRheGFfc3VtcyguKSA+IDAsIC4pDQogICAgICAgICAgICAgICAgIHNhbXBsZV9kYXRhKHBzX3NwZWNpZXMpID0gc2FtcGxlX2RhdGEocHNfc3BlY2llcykgJT4lIA0KICAgICAgICAgICAgICAgICAgIGFzKCdkYXRhLmZyYW1lJykgJT4lDQogICAgICAgICAgICAgICAgICAgbXV0YXRlKFRpc3N1ZVR5cGUgPSBmY3RfcmVsZXZlbChUaXNzdWVUeXBlLCAnT3Z1bGUnKSkNCiAgICAgICAgICAgICAgICAgcmV0dXJuKHBzX3NwZWNpZXMpfSkNCnBzX3NwZWNpZXNfcmEgPSBtYXAocHNfc3BlY2llcywgfnRyYW5zZm9ybV9zYW1wbGVfY291bnRzKC54LCBmdW5jdGlvbih4KXt4IC8gc3VtKHgpfSkpDQpwc19zcGVjaWVzX2NsciA9IG1hcChwc19zcGVjaWVzLCBtaWNyb2Jpb21lOjp0cmFuc2Zvcm0sICdjbHInKQ0KcHNfc3BlY2llc19hbHIgPSBtYXAocHNfc3BlY2llcywgbWljcm9iaW9tZTo6dHJhbnNmb3JtLCAnYWxyJywgc2hpZnQ9MSkNCmBgYA0KDQpNb3N0IHByZXZhbGVudCBnZW5lcmENCmBgYHtyfQ0KcHJldl9jb3JuX2dlbnVzID0gbWFwKHBzX2dlbnVzX3JhLA0KICAgICAgICAgICAgZnVuY3Rpb24ocHNfZ2VudXNfcmEpew0KICAgICAgICAgICAgcmVsYXRpdmVfY291bnRzID0gcHNfZ2VudXNfcmEgJT4lIGdldF9jb3VudHMoKQ0KICAgICAgICAgICAgICB0YXggPSBwc19nZW51c19yYSAlPiUgZ2V0X3RheCgpDQogICAgICAgICAgICAgIHJlbGF0aXZlX2NvdW50cyAlPiUgDQogICAgICAgICAgICAgICAgcGl2b3RfbG9uZ2VyKC1mZWF0dXJlX2lkLCBuYW1lc190byA9ICdTYW1wbGVJRCcsIHZhbHVlc190byA9ICdjb3VudHMnKSAlPiUNCiAgICAgICAgICAgICAgICBsZWZ0X2pvaW4obWV0YWRhdGEsIGJ5PSdTYW1wbGVJRCcpICU+JQ0KICAgICAgICAgICAgICAgIGxlZnRfam9pbih0YXgsIGJ5PSdmZWF0dXJlX2lkJykgJT4lDQogICAgICAgICAgICAgICAgZ3JvdXBfYnkoR2VudXMpICU+JQ0KICAgICAgICAgICAgICAgIG11dGF0ZShwcmV2YWxlbmNlX2VudGlyZV9kYXRhc2V0ID0gc3VtKGNvdW50cyA+IDApIC8gbigpLA0KICAgICAgICAgICAgICAgICAgICAgICBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCA9IG1lYW4oY291bnRzKSkgJT4lDQogICAgICAgICAgICAgICAgZ3JvdXBfYnkoR2VudXMsIENvcm5fR2Vub3R5cGUpICU+JQ0KICAgICAgICAgICAgICAgIHN1bW1hcml6ZShwcmV2YWxlbmNlID0gc3VtKGNvdW50cyA+IDApIC8gbigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSA9IG1lYW4oY291bnRzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmFsZW5jZV9lbnRpcmVfZGF0YXNldCA9IGZpcnN0KHByZXZhbGVuY2VfZW50aXJlX2RhdGFzZXQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCA9IGZpcnN0KG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0KSkgJT4lDQogICAgICAgICAgICAgICAgdW5ncm91cCgpfSkNCnByZXZfY29ybl9nZW51cyRgMTZTYCAlPiUgDQogIHJlbmFtZSh0b3RhbCA9IG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0KSAlPiUNCiAgZGlzdGluY3QoR2VudXMsIENvcm5fR2Vub3R5cGUsIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCB0b3RhbCkgJT4lDQogIG11dGF0ZShtZWFuX3JlbGF0aXZlX2FidW5kYW5jZT0gcm91bmQobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIDMpLA0KICAgICAgICAgdG90YWwgPSByb3VuZCh0b3RhbCwgMykpICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ29ybl9HZW5vdHlwZSwgdmFsdWVzX2Zyb20gPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSkgJT4lDQogIGZpbHRlcih0b3RhbCA+PSAwLjAxKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgJT4lDQogIGtibChmb3JtYXQgPSAnaHRtbCcsIGNvbC5uYW1lcyA9IGMoJ0dlbnVzJywgJ1RvdGFsIFJlbGF0aXZlIEFidW5kYW5jZScsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdSZWxhdGl2ZSBhYnVuZGFuY2UgQjczJywgJ1JlbGF0aXZlIGFidW5kYW5jZSBDTUwzMjInKSkgJT4lDQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEYsIGh0bWxfZm9udCA9ICJUaW1lcyBOZXcgUm9tYW4iKQ0KcHJldl9jb3JuX2dlbnVzJElUUyAlPiUgDQogIHJlbmFtZSh0b3RhbCA9IG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0KSAlPiUNCiAgZGlzdGluY3QoR2VudXMsIENvcm5fR2Vub3R5cGUsIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlLCB0b3RhbCkgJT4lDQogIG11dGF0ZShtZWFuX3JlbGF0aXZlX2FidW5kYW5jZT0gcm91bmQobWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIDMpLA0KICAgICAgICAgdG90YWwgPSByb3VuZCh0b3RhbCwgMykpICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ29ybl9HZW5vdHlwZSwgdmFsdWVzX2Zyb20gPSBtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSkgJT4lDQogICNmaWx0ZXIodG90YWwgPj0gMC4wMSkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbCkpICU+JQ0KICBrYmwoZm9ybWF0ID0gJ2h0bWwnLCBjb2wubmFtZXMgPSBjKCdHZW51cycsICdUb3RhbCBSZWxhdGl2ZSBBYnVuZGFuY2UnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmVsYXRpdmUgYWJ1bmRhbmNlIEI3MycsICdSZWxhdGl2ZSBhYnVuZGFuY2UgQ01MMzIyJykpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiVGltZXMgTmV3IFJvbWFuIikNCmBgYA0KTW9zdCBwcmV2YWxlbnQgc3BlY2llcw0KYGBge3J9DQpwcmV2X2Nvcm5fc3BlY2llcyA9IG1hcChwc19zcGVjaWVzX3JhLA0KICAgICAgICAgICAgZnVuY3Rpb24ocHNfc3BlY2llc19yYSl7DQogICAgICAgICAgICByZWxhdGl2ZV9jb3VudHMgPSBwc19zcGVjaWVzX3JhICU+JSBnZXRfY291bnRzKCkNCiAgICAgICAgICAgICAgdGF4ID0gcHNfc3BlY2llc19yYSAlPiUgZ2V0X3RheCgpDQogICAgICAgICAgICAgIHJlbGF0aXZlX2NvdW50cyAlPiUgDQogICAgICAgICAgICAgICAgcGl2b3RfbG9uZ2VyKC1mZWF0dXJlX2lkLCBuYW1lc190byA9ICdTYW1wbGVJRCcsIHZhbHVlc190byA9ICdjb3VudHMnKSAlPiUNCiAgICAgICAgICAgICAgICBsZWZ0X2pvaW4obWV0YWRhdGEsIGJ5PSdTYW1wbGVJRCcpICU+JQ0KICAgICAgICAgICAgICAgIGxlZnRfam9pbih0YXgsIGJ5PSdmZWF0dXJlX2lkJykgJT4lDQogICAgICAgICAgICAgICAgZ3JvdXBfYnkoU3BlY2llcykgJT4lDQogICAgICAgICAgICAgICAgbXV0YXRlKHByZXZhbGVuY2VfZW50aXJlX2RhdGFzZXQgPSBzdW0oY291bnRzID4gMCkgLyBuKCksDQogICAgICAgICAgICAgICAgICAgICAgIG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0ID0gbWVhbihjb3VudHMpKSAlPiUNCiAgICAgICAgICAgICAgICBncm91cF9ieShTcGVjaWVzLCBDb3JuX0dlbm90eXBlKSAlPiUNCiAgICAgICAgICAgICAgICBzdW1tYXJpemUocHJldmFsZW5jZSA9IHN1bShjb3VudHMgPiAwKSAvIG4oKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UgPSBtZWFuKGNvdW50cyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHByZXZhbGVuY2VfZW50aXJlX2RhdGFzZXQgPSBmaXJzdChwcmV2YWxlbmNlX2VudGlyZV9kYXRhc2V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2VfZW50aXJlX2RhdGFzZXQgPSBmaXJzdChtZWFuX3JlbGF0aXZlX2FidW5kYW5jZV9lbnRpcmVfZGF0YXNldCkpICU+JQ0KICAgICAgICAgICAgICAgIHVuZ3JvdXAoKX0pDQpwcmV2X2Nvcm5fc3BlY2llcyRgMTZTYCAlPiUgDQogIHJlbmFtZSh0b3RhbCA9IG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0KSAlPiUNCiAgZGlzdGluY3QoU3BlY2llcywgQ29ybl9HZW5vdHlwZSwgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIHRvdGFsKSAlPiUNCiAgbXV0YXRlKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlPSByb3VuZChtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSwgMyksDQogICAgICAgICB0b3RhbCA9IHJvdW5kKHRvdGFsLCAzKSkgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBDb3JuX0dlbm90eXBlLCB2YWx1ZXNfZnJvbSA9IG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlKSAlPiUNCiAgZmlsdGVyKHRvdGFsID49IDAuMDEpICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWwpKSAlPiUNCiAga2JsKGZvcm1hdCA9ICdodG1sJywgY29sLm5hbWVzID0gYygnU3BlY2llcycsICdUb3RhbCBSZWxhdGl2ZSBBYnVuZGFuY2UnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmVsYXRpdmUgYWJ1bmRhbmNlIEI3MycsICdSZWxhdGl2ZSBhYnVuZGFuY2UgQ01MMzIyJykpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiVGltZXMgTmV3IFJvbWFuIikNCnByZXZfY29ybl9zcGVjaWVzJElUUyAlPiUgDQogIHJlbmFtZSh0b3RhbCA9IG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlX2VudGlyZV9kYXRhc2V0KSAlPiUNCiAgZGlzdGluY3QoU3BlY2llcywgQ29ybl9HZW5vdHlwZSwgbWVhbl9yZWxhdGl2ZV9hYnVuZGFuY2UsIHRvdGFsKSAlPiUNCiAgbXV0YXRlKG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlPSByb3VuZChtZWFuX3JlbGF0aXZlX2FidW5kYW5jZSwgMyksDQogICAgICAgICB0b3RhbCA9IHJvdW5kKHRvdGFsLCAzKSkgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBDb3JuX0dlbm90eXBlLCB2YWx1ZXNfZnJvbSA9IG1lYW5fcmVsYXRpdmVfYWJ1bmRhbmNlKSAlPiUNCiAgZmlsdGVyKHRvdGFsID49IDAuMDEpICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWwpKSAlPiUNCiAga2JsKGZvcm1hdCA9ICdodG1sJywgY29sLm5hbWVzID0gYygnU3BlY2llcycsICdUb3RhbCBSZWxhdGl2ZSBBYnVuZGFuY2UnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmVsYXRpdmUgYWJ1bmRhbmNlIEI3MycsICdSZWxhdGl2ZSBhYnVuZGFuY2UgQ01MMzIyJykpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiVGltZXMgTmV3IFJvbWFuIikNCmBgYA0KYGBge3J9DQpyZWFkcyA9IGxpc3QoJzE2UycgPSByZWFkX3F6YShoZXJlKCdkYXRhJywgJzE2UycsICdyZXAtc2Vxcy1maWx0ZXJlZC5xemEnKSkkZGF0YSwNCiAgICAgICAgICAgICAnSVRTJyA9IHJlYWRfcXphKGhlcmUoJ2RhdGEnLCAnSVRTJywgJ3JlcC1zZXFzLWZpbHRlcmVkLnF6YScpKSRkYXRhKQ0KYGBgDQoNCkJlbG93IGFyZSBiYXJwbG90cyBvZiByZWxhdGl2ZSB0YXhvbiBhYnVuZGFuY2VzIGZvciAxNlMgc2VxdWVuY2luZyB3aXRoIHNhbXBsZXMgZ3JvdXBlZCBhY2NvcmRpbmcgdG8gc2ltaWxhcml0eSB1c2luZyB0aGUgbmVhdG1hcCBtZXRob2QuIA0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEwLCB3YXJuaW5nPUZBTFNFLCBmaWcuc2hvdz0naGlkZSd9DQojIyBodHRwczovL2dpdGh1Yi5jb20vZ29vZ2xlL3BhbGV0dGUuanMvYmxvYi83OWE3MDNkZjM0NGUzYjI0MzgwY2UxYTIxMWEyZGY3ZjJkOTBjYTIyL3BhbGV0dGUuanMjTDgwMg0KbXBuNjUgPSBjKCcjZmYwMDI5JywnIzM3N2ViOCcsJyM2NmE2MWUnLCcjOTg0ZWEzJywnIzAwZDJkNScsJyNmZjdmMDAnLCcjYWY4ZDAwJywnIzdmODBjZCcsJyNiM2U5MDAnLCcjYzQyZTYwJywnI2E2NTYyOCcsDQogICAgICAgICAnI2Y3ODFiZicsJyM4ZGQzYzcnLCcjYmViYWRhJywnI2ZiODA3MicsJyM4MGIxZDMnLCcjZmRiNDYyJywnI2ZjY2RlNScsJyNiYzgwYmQnLCcjZmZlZDZmJywnI2M0ZWFmZicsJyNjZjhjMDAnLA0KICAgICAgICAgJyMxYjllNzcnLCcjZDk1ZjAyJywnI2U3Mjk4YScsJyNlNmFiMDInLCcjYTY3NjFkJywnIzAwOTdmZicsJyMwMGQwNjcnLCcjMDAwMDAwJywnIzI1MjUyNScsJyM1MjUyNTInLCcjNzM3MzczJywNCiAgICAgICAgICcjOTY5Njk2JywnI2JkYmRiZCcsJyNmNDM2MDAnLCcjNGJhOTNiJywnIzU3NzliYicsJyM5MjdhY2MnLCcjOTdlZTNmJywnI2JmMzk0NycsJyM5ZjViMDAnLCcjZjQ4NzU4JywnIzhjYWVkNicsDQogICAgICAgICAnI2YyYjk0ZicsJyNlZmYyNmUnLCcjZTQzODcyJywnI2Q5YjEwMCcsJyM5ZDdhMDAnLCcjNjk4Y2ZmJywnI2Q5ZDlkOScsJyMwMGQyN2UnLCcjZDA2ODAwJywnIzAwOWY4MicsJyNjNDkyMDAnLA0KICAgICAgICAgJyNjYmU4ZmYnLCcjZmVjZGRmJywnI2MyN2ViNicsJyM4Y2QyY2UnLCcjYzRiOGQ5JywnI2Y4ODNiMCcsJyNhNDkxMDAnLCcjZjQ4ODAwJywnIzI3ZDBkZicsJyNhMDRhOWInKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0NCm1hcChyYW5rX25hbWVzKHBzX2dlbnVzJGAxNlNgKVsyOjZdLCBmdW5jdGlvbih0YXhfcmFuayl7DQogIGRmID0gcHNfZ2VudXMkYDE2U2AgJT4lIA0KICAgIHNwZWVkeXNlcTo6bXV0YXRlX3NhbXBsZV9kYXRhKGNvbmRpdGlvbiA9IGNvbmRpdGlvbl93X3JlcCkgJT4lDQogICAgdHJhbnNmb3JtKHRyYW5zZm9ybSA9ICJjb21wb3NpdGlvbmFsIikgJT4lDQogICAgYWdncmVnYXRlX3JhcmUobGV2ZWwgPSB0YXhfcmFuaywgZGV0ZWN0aW9uID0gMC4wNSwgcHJldmFsZW5jZSA9IDAuMDUpIA0KICBwID0gcGxvdF9jb21wb3NpdGlvbihkZiwgeC5sYWJlbD0nY29uZGl0aW9uJywgb3R1LnNvcnQgPSAnYWJ1bmRhbmNlJywgc2FtcGxlLnNvcnQ9J25lYXRtYXAnKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAxKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9bXBuNjUpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0wLCB2anVzdD0wLjUpKSArDQogIGxhYnMoeCA9ICJTYW1wbGUgY29uZGl0aW9uIiwNCiAgICAgICB5ID0gIlJlbGF0aXZlIGFidW5kYW5jZSIsDQogICAgICAgdGl0bGUgPSBnbHVlKCIxNlMgUmVsYXRpdmUgYWJ1bmRhbmNlIGF0IHt0YXhfcmFua30gbGV2ZWwiKSwgDQogICAgICAgZmlsbCA9IHRheF9yYW5rKQ0KICAgICBwICU+JSBwbG90bHk6OmdncGxvdGx5KCkNCn0pDQpgYGANCg0KDQo8YnI+PGJyPjxicj48YnI+PGJyPjxicj4gVGhlIG5leHQgdHdvIHNldHMgYXJlIGRvbmUgd2l0aCBJVFMgY291bnRzIGJ1dCBtYWRlIHRoZSBzYW1lIHdheSBhcyBhYm92ZS4NCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQ0KbWFwKHJhbmtfbmFtZXMocHNfZ2VudXMkSVRTKVsyOjZdLCBmdW5jdGlvbih0YXhfcmFuayl7DQogIGRmID0gcHNfZ2VudXMkSVRTICU+JSANCiAgICBzcGVlZHlzZXE6Om11dGF0ZV9zYW1wbGVfZGF0YShjb25kaXRpb24gPSBjb25kaXRpb25fd19yZXApICU+JQ0KICAgIHRyYW5zZm9ybSh0cmFuc2Zvcm0gPSAiY29tcG9zaXRpb25hbCIpICU+JQ0KICAgIGFnZ3JlZ2F0ZV9yYXJlKGxldmVsID0gdGF4X3JhbmssIGRldGVjdGlvbiA9IDAuMDUsIHByZXZhbGVuY2UgPSAwLjA1KSANCiAgcCA9IHBsb3RfY29tcG9zaXRpb24oZGYsIHgubGFiZWw9J2NvbmRpdGlvbicsIG90dS5zb3J0ID0gJ2FidW5kYW5jZScsIHNhbXBsZS5zb3J0PSduZWF0bWFwJykgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChuY29sID0gMSkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPW1wbjY1KSArDQogIHRoZW1lX21pbmltYWwoKSArIA0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsaGp1c3Q9MCwgdmp1c3Q9MC41KSkgKw0KICBsYWJzKHggPSAiU2FtcGxlIGNvbmRpdGlvbiIsDQogICAgICAgeSA9ICJSZWxhdGl2ZSBhYnVuZGFuY2UiLA0KICAgICAgIHRpdGxlID0gZ2x1ZSgiSVRTIFJlbGF0aXZlIGFidW5kYW5jZSBhdCB7dGF4X3Jhbmt9IGxldmVsIiksIA0KICAgICAgIGZpbGwgPSB0YXhfcmFuaykNCiAgcCAlPiUgcGxvdGx5OjpnZ3Bsb3RseSgpDQp9KQ0KYGBgDQoNCg0KYGBge3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD04LCB3YXJuaW5nPUZBTFNFfQ0KcHJ1bmVfdGF4YShuYW1lcyhzb3J0KHRheGFfc3Vtcyhwc19nZW51c19yYSRgMTZTYCksZGVjcmVhc2luZyA9IFRSVUUpWzE6MzBdKSwgcHNfZ2VudXNfcmEkYDE2U2ApICU+JQ0KICBzcGVlZHlzZXE6OnBsb3RfaGVhdG1hcChtZXRob2QgPSAiTk1EUyIsIGRpc3RhbmNlID0gImJyYXkiLCBzYW1wbGUubGFiZWwgPSAnY29uZGl0aW9uJywgdGF4YS5sYWJlbD0nR2VudXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0wLCB2anVzdD0wLjUsIHNpemUgPSAxMCksDQogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjIpKSArDQogIGxhYnModGl0bGUgPSAnMTZTIEhlYXRtYXAgb2YgdG9wIDMwIG1vc3QgYWJ1bmRhbnQgZ2VuZXJhJykNCmBgYA0KDQo8YnI+PGJyPjxicj48YnI+PGJyPjxicj4NCg0KYGBge3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD04LCB3YXJuaW5nPUZBTFNFfQ0KcHJ1bmVfdGF4YShuYW1lcyhzb3J0KHRheGFfc3Vtcyhwc19nZW51c19yYSRJVFMpLGRlY3JlYXNpbmcgPSBUUlVFKVsxOjMwXSksIHBzX2dlbnVzX3JhJElUUykgJT4lDQogIHNwZWVkeXNlcTo6cGxvdF9oZWF0bWFwKG1ldGhvZCA9ICJOTURTIiwgZGlzdGFuY2UgPSAiYnJheSIsIHNhbXBsZS5sYWJlbCA9ICdjb25kaXRpb24nLCB0YXhhLmxhYmVsPSdHZW51cycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTkwLGhqdXN0PTAsIHZqdXN0PTAuNSwgc2l6ZSA9IDEwKSwNCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMikpICsNCiAgbGFicyh0aXRsZSA9ICdJVFMgSGVhdG1hcCBvZiB0b3AgMzAgbW9zdCBhYnVuZGFudCBnZW5lcmEnKQ0KYGBgDQpgYGB7cn0NCnNhdmUuaW1hZ2UoaGVyZSgnc3JjLzE2X2FuZF9JVFNfaW1wb3J0LlJEYXRhJykpDQpgYGANCg0K